package com.hgy.common.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 类操作工具类
 * 
 * @author alone
 *
 */
public final class ClassUtil {
	
	
	private static final Logger LOOGER = LoggerFactory.getLogger(ClassUtil.class);
	
	/**
	 * 获取类加载器
	 * @return
	 */
	public static ClassLoader getClassLoader(){
		return Thread.currentThread().getContextClassLoader();
	}
	
	/**
	 * 加载类
	 * 
	 * @param className
	 * @param isInitialized
	 * @return
	 */
	public static Class<?> loadClass(String className, boolean isInitialized){
		Class<?> cls;
		
		try {
			cls = Class.forName(className, isInitialized, getClassLoader());
		} catch (ClassNotFoundException e) {
			LOOGER.error("load class failure", e);
			throw new RuntimeException(e);
		}
		return cls;
	}
	
	/**
	 * 默认不初始化
	 * 
	 * @param className
	 * @return
	 */
	public static Class<?> loadClass(String className){
		return loadClass(className, false);
	}
	
	
	/**
	 * 获取指定包名下的类
	 * 
	 * @param packName
	 * @return
	 */
	public static Set<Class<?>> getClassSet(String packageName){
		
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		
		try {
			Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
			
			while(urls.hasMoreElements()){
				URL url = urls.nextElement();
				
				if(url != null){
					String protocol = url.getProtocol();
					// class文件
					if(protocol.equals("file")){
						String packagePath = url.getPath().substring(1).replaceAll("%20", " ");
						addClass(classSet, packagePath, packageName);
					}else if (protocol.equals("jar")) {
						JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
						if(jarURLConnection != null){
							JarFile jarFile = jarURLConnection.getJarFile();
							if(jarFile != null){
								Enumeration<JarEntry> jarEntries = jarFile.entries();
								while(jarEntries.hasMoreElements()){
									JarEntry jarEntry = jarEntries.nextElement();
									String className = jarEntry.getName();
									if (className.endsWith(".class")) {
										className.substring(0, className.lastIndexOf(".")).replaceAll("/", ".");
										doAddClass(classSet, className);
									}
								}
							}
						}
					}
				}
			}
			
			
		} catch (IOException e) {
			LOOGER.error("get class set failure", e);
			throw new RuntimeException(e);
		}
		return classSet;
		
	}
	

	private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName){
		File[] files = new File(packagePath).listFiles(new FileFilter() {
			//文件过滤
			@Override
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
			}
		});
		
		for (File file : files) {
			// 获取子文件夹名（即 controller helper service model文件夹）
			String fileName = file.getName();
			if(file.isFile()){
				String className = fileName.substring(0, fileName.lastIndexOf("."));
				if(StringUtil.isNotEmpty(packageName)){
					className = packageName + "." + className;
				}
				doAddClass(classSet, className);
			}else {
				// 子文件夹路径
				String subPackagePath = fileName;
				if(StringUtil.isNotEmpty(packageName)){
					subPackagePath = packagePath + "/" + subPackagePath;
					
				}
				// 子文件夹名(com.hgy.chapter3.controller)
				String subPackageName = fileName;
				if(StringUtil.isNotEmpty(subPackageName)){
					subPackageName = packageName + "." + subPackageName;
				}
				
				// 递归查询
				addClass(classSet, subPackagePath, subPackageName);
			}
		}
	}
	
	private static void doAddClass(Set<Class<?>> classSet, String className) {
		Class<?> cls = loadClass(className, false);
		classSet.add(cls);
	}
}
